﻿using Avalonia.Controls.ApplicationLifetimes;
using DX.IO;
using DX.ViewModels;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;

namespace DX
{
    public static class HostExtensions
    {
       
        static void OnInit(this IServiceCollection services)
        {
            services.AddJson();
            services.AddSingleton<IApplicationBuilder, ApplicationBuilder>();
            services.AddSingleton<IClassicDesktopStyleApplicationLifetime, ClassicDesktopStyleApplicationLifetime>();
            services.AddScoped<ViewModelContext>();
            services.AddSingleton<INotifyCenter, DefaultNotifyCenter>();
            services.AddSingleton<ICloseStrategy, DefaultCloseStrategy>();
            services.AddSingleton<IMessageCenter, DefaultMessageCenter>();
            services.AddSingleton<IFileSystemDialog, DefaultFileSystemDialog>();
        }


        public static void AddForm<TApp>(this IServiceCollection services, Action<FormOption> action) where TApp : Avalonia.Application
        {
            services.AddSingleton<AppStart, AppStart<TApp>>();
            services.AddSingleton<Avalonia.Application, TApp>();
            services.AddSingleton<IFormRoutFactory, FormRoutFactory>();
            services.AddSingleton<IRouterFactory>(s => s.GetService<IFormRoutFactory>());
            IConfiguration configuration = services.GetInstance<IConfiguration>();
            services.Configure<FormOption>(configuration.GetSection("mvvm"));
            services.PostConfigure<FormOption>(action);
        }
        public static void AddRouter<TApp>(this IServiceCollection services, Action<RouterOption> action) where TApp : Avalonia.Application
        {
            services.AddSingleton<AppStart, AppStart<TApp>>();
            services.AddSingleton<Avalonia.Application, TApp>();
            services.AddSingleton<IUrlRoutFactory, UrlRoutFactory>();
            services.AddSingleton<IRouterFactory>(s => s.GetService<IUrlRoutFactory>());
            IConfiguration configuration = services.GetInstance<IConfiguration>();
            services.Configure<RouterOption>(configuration.GetSection("mvvm"));
            services.PostConfigure<RouterOption>(action);
        }

        public static IHost CreateApp<T>() where T : class
        {
            try
            {
                var type = typeof(T);
                var constructor = type.GetConstructors().FirstOrDefault();
                if (constructor == null) throw new HostException($"{type.FullName} not exist constructor");

                var hostBuilder = Host.CreateApplicationBuilder();
                T tStartUp = default;
                var services = hostBuilder.Services;
                services.OnInit();
                //    services.AddSingleton<ApplicationContext>(GetContext);
                var constructorArgs = constructor.GetParameters();
                var env = services.FirstOrDefault(n => n.ServiceType == typeof(IHostEnvironment)).ImplementationInstance as IHostEnvironment;
                var config = services.FirstOrDefault(n => n.ServiceType == typeof(IConfiguration)).ImplementationFactory(null) as IConfiguration;

                if (constructorArgs.Length == 0)
                {
                    tStartUp = System.Activator.CreateInstance(type) as T;
                }
                else
                {
                    object[] args = constructorArgs.Select(n => services.GetInstance(n.ParameterType)).ToArray();
                    tStartUp = constructor.Invoke(args) as T;
                }
                var startUp = tStartUp as IStartUp;
                if (startUp != null)
                {
                    startUp.ConfigureServices(services);
                }
                else
                {
                    var method = tStartUp.GetType().GetMethod(nameof(IStartUp.ConfigureServices), new Type[] { typeof(IServiceCollection) });
                    method?.Invoke(tStartUp, new object[] { services });
                }

                var host = hostBuilder.Build();
                var appBuilder = host.Services.GetService<IApplicationBuilder>();
                if (startUp != null)
                {
                    startUp.Configure(appBuilder, env);
                }
                else
                {
                    var method = tStartUp.GetType().GetMethod(nameof(IStartUp.Configure));
                    if (method != null)
                    {
                        var args = method.GetParameters().Select(n => host.Services.GetService(n.ParameterType)).ToArray();
                        method.Invoke(tStartUp, args);
                    }
                }
                host.Services.GetService<AppStart>();

                return host;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }


        }
    }
}
